/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.csvgenerator.inputmodel.parser;

import com.csvgenerator.engine.value.ValueProducer;
import com.csvgenerator.engine.value.ValueProducerDoesntExistException;
import com.csvgenerator.engine.value.ValueProducerLookup;
import com.csvgenerator.engine.value.ValueProducerWithIdExistsException;
import com.csvgenerator.engine.vc.ConcatenatorValueCombinator;
import com.csvgenerator.engine.vc.MultiplyValueCombinator;
import com.csvgenerator.engine.vg.FixedNumberValueGenerator;
import com.csvgenerator.engine.vg.FixedTextValueGenerator;
import com.csvgenerator.engine.vg.LinearRandomValueGenerator;
import com.csvgenerator.engine.vg.LinearValueGenerator;
import com.csvgenerator.engine.vg.NumberValueGenerator;
import com.csvgenerator.engine.vg.RandomDateValueGenerator;
import com.csvgenerator.engine.vg.RandomValueGenerator;
import com.csvgenerator.engine.vg.SetValueGenerator;
import com.csvgenerator.engine.vm.ReverseValueModifier;
import com.csvgenerator.engine.vr.SimpleValueReferencer;
import com.csvgenerator.settings.GlobalConstants;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author Administrator
 */
public class InputModelSAXHandler extends DefaultHandler {

    private String fullClassName;
    private ValueProducer vp;
    private String currentElement;
    private StringBuilder sb = new StringBuilder();

    @Override
    public void startDocument() throws SAXException {
        System.out.println("Starting reading InputModel file ");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.endsWith("ValueGenerator")) {
            handleComplexElement(qName, attributes);
        } else if (qName.endsWith("ValueCombinator")) {
            handleComplexElement(qName, attributes);
        } else if (qName.endsWith("ValueModifier")) {
            handleComplexElement(qName, attributes);
        } else if (qName.endsWith("ValueReferencer")) {
            handleComplexElement(qName, attributes);
        } else {
            currentElement = qName;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        handleElement(qName, sb.toString().trim());
        currentElement = null;
        sb.setLength(0);
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.println("Finished reading InputModel file ");
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        sb.append(ch, start, length);
    }

    
    /**
     * Creates new ValueProducer and sets it as current vp. Also handles basic 
     * attributes. 
     * @param name Name of complex element that starts
     * @param atts Attributes of complex element (id,disables or hidden)
     */
    private void handleComplexElement(String name, Attributes atts) {
        if (atts.getIndex("id") == -1) {
            System.out.println("Fatal error reading InputModel file, id of Value Producer is not specified");
            System.exit(1);
        }
        Long id = Long.parseLong(atts.getValue("id"));
        try {
            fullClassName = ValueProducerLookup.getInstance().getFullClassName(name);
            if (!ValueProducerLookup.getInstance().valueProducerExists(id)) {
                vp = ValueProducerLookup.getInstance().createValueProducer(fullClassName);
                vp.setId(id);
                ValueProducerLookup.getInstance().addValueProducer(id, vp);
            } else {
                System.out.println("Value Producer with id " + id + " already exists. Fatal error reading InputModel file");
                System.exit(1);
            }
            handleValueProducerAttributes(atts);
        } catch (ValueProducerWithIdExistsException ex) {
            System.out.println(ex);
            System.exit(1);
        } catch (UnknownAttributeException ex) {
            System.out.println(ex);
            System.exit(1);
        } catch (ClassNotFoundException ex) {
            System.out.println("Value Producer Type <" + name + "> not found! Fatal error reading InputModel file" + ex);
            System.exit(1);
        }
    }

    /**
     * Sets attributes to ValueProducer
     * @param atts Attributes map
     * @throws UnknownAttributeException 
     */
    private void handleValueProducerAttributes(Attributes atts) throws UnknownAttributeException {
        String attribute = null;
        for (int i = 0; i < atts.getLength(); i++) {
            attribute = atts.getQName(i);
            if (attribute.equalsIgnoreCase("id")) {
                continue;
            }
            if (attribute.equalsIgnoreCase("disabled")) {
                vp.setDisabled(Boolean.parseBoolean(atts.getValue(attribute)));
                continue;
            }
            if (attribute.equalsIgnoreCase("hidden")) {
                vp.setHidden(Boolean.parseBoolean(atts.getValue(attribute)));
                continue;
            }
            throw new UnknownAttributeException(attribute);
        }
    }

    /**
     * Handles element ending and populates corresponding filed in ValueProducer
     * @param name Name of element that is ended
     * @param value Value of element to be initialized with
     */
    private void handleElement(String name, String value) {

        try {

            // <editor-fold defaultstate="collapsed" desc="FixedTextValueGenerator">
            if (vp instanceof FixedTextValueGenerator) {
                //element ends so it has the same name like current vp
                if (name.equalsIgnoreCase(FixedTextValueGenerator.class.getSimpleName())) {
                    return;
                }

                if (name.equalsIgnoreCase("FixedText")) {
                    ((FixedTextValueGenerator) vp).setFixedText(value);
                    return;
                }
                if (name.equalsIgnoreCase("BlankSpace")) {
                    ((FixedTextValueGenerator) vp).setBlankSpace(GlobalConstants.blankSpaceType(value));
                    return;
                }
                if (name.equalsIgnoreCase("NewLine")) {
                    ((FixedTextValueGenerator) vp).setNewLine(GlobalConstants.newLineType(value));
                    return;
                }
                //add more elements if exist
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            //</editor-fold>

            // <editor-fold defaultstate="collapsed" desc="FixedNumberValueGenerator">
            if (vp instanceof FixedNumberValueGenerator) {
                if (name.equalsIgnoreCase(FixedNumberValueGenerator.class.getSimpleName())) {
                    return;
                }

                if (name.equalsIgnoreCase("FixedNumber")) {
                    System.out.println("name: " + name);
                    System.out.println("value: " + value);
                    ((FixedNumberValueGenerator) vp).setFixedNumber(Long.parseLong(value));
                    return;
                }
                //add more elements if exist
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            //</editor-fold>

            // <editor-fold defaultstate="collapsed" desc="LinearValueGenerator">            
            if (vp instanceof LinearValueGenerator) {
                if (name.equalsIgnoreCase(LinearValueGenerator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("LowerBound")) {
                    ((LinearValueGenerator) vp).setLowerBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("UpperBound")) {
                    ((LinearValueGenerator) vp).setUpperBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Step")) {
                    ((LinearValueGenerator) vp).setStep(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Mod")) {
                    ((LinearValueGenerator) vp).setMod(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((LinearValueGenerator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((LinearValueGenerator) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());
            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="RandomValueGenerator">            
            if (vp instanceof RandomValueGenerator) {
                if (name.equalsIgnoreCase(RandomValueGenerator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("LowerBound")) {
                    ((RandomValueGenerator) vp).setLowerBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("UpperBound")) {
                    ((RandomValueGenerator) vp).setUpperBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Gravity")) {
                    ((RandomValueGenerator) vp).setGravity(Float.parseFloat(value));
                    return;
                }
                if (name.equalsIgnoreCase("Mod")) {
                    ((RandomValueGenerator) vp).setMod(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((RandomValueGenerator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((RandomValueGenerator) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());
            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="LinearRandomValueGenerator">            
            if (vp instanceof LinearRandomValueGenerator) {
                if (name.equalsIgnoreCase(LinearRandomValueGenerator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("LowerBound")) {
                    ((LinearRandomValueGenerator) vp).setLowerBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("UpperBound")) {
                    ((LinearRandomValueGenerator) vp).setUpperBound(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Gravity")) {
                    ((LinearRandomValueGenerator) vp).setGravity(Float.parseFloat(value));
                    return;
                }
                if (name.equalsIgnoreCase("Step")) {
                    ((LinearRandomValueGenerator) vp).setStep(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Mod")) {
                    ((LinearRandomValueGenerator) vp).setMod(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((LinearRandomValueGenerator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((LinearRandomValueGenerator) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());
            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="SetValueGenerator">            
            if (vp instanceof SetValueGenerator) {
                if (name.equalsIgnoreCase(SetValueGenerator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("SizeSampler")) {
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ValueProducer nvp = ValueProducerLookup.getInstance().getValueProducer(refId);
                    if (nvp instanceof NumberValueGenerator) {
                        ((SetValueGenerator) vp).setSizeSampler((NumberValueGenerator) nvp);
                    } else {
                        throw new NumberValueProducerExpectedException(refId);
                    }
                    return;
                }
                if (name.equalsIgnoreCase("IndexSampler")) {
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ValueProducer nvp = ValueProducerLookup.getInstance().getValueProducer(refId);
                    if (nvp instanceof NumberValueGenerator) {
                        ((SetValueGenerator) vp).setIndexSampler((NumberValueGenerator) nvp);
                    } else {
                        throw new NumberValueProducerExpectedException(refId);
                    }
                    return;
                }
                if (name.equalsIgnoreCase("ProducerReference")) {
                    //TODO check for self reference
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ((SetValueGenerator) vp).getProducerReferences().add(ValueProducerLookup.getInstance().getValueProducer(refId));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((SetValueGenerator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Infix")) {
                    ((SetValueGenerator) vp).setInfix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((SetValueGenerator) vp).setSuffix(value);
                    return;
                }
                if (name.equalsIgnoreCase("UniqueValues")) {
                    ((SetValueGenerator) vp).setUniqueValues(Boolean.parseBoolean(value));
                    return;
                }

                if (name.equalsIgnoreCase("FixedValue")) {
                    //TODO check for self reference
                    ((SetValueGenerator) vp).getFixedValues().add(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());
            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="RandomDateValueGenerator">            
            if (vp instanceof RandomDateValueGenerator) {
                if (name.equalsIgnoreCase(RandomDateValueGenerator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("LowerBound")) {
                    ((RandomDateValueGenerator) vp).setLowerBound(value);
                    return;
                }
                if (name.equalsIgnoreCase("UpperBound")) {
                    ((RandomDateValueGenerator) vp).setUpperBound(value);
                    return;
                }
                if (name.equalsIgnoreCase("Gravity")) {
                    ((RandomDateValueGenerator) vp).setGravity(Float.parseFloat(value));
                    return;
                }
                if (name.equalsIgnoreCase("Mod")) {
                    ((RandomDateValueGenerator) vp).setMod(Long.parseLong(value));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((RandomDateValueGenerator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((RandomDateValueGenerator) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());
            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="ConcatenatorValueCombinator">
            if (vp instanceof ConcatenatorValueCombinator) {
                if (name.equalsIgnoreCase(ConcatenatorValueCombinator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("ProducerReference")) {
                    //TODO check for self reference
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ((ConcatenatorValueCombinator) vp).getProducerReferences().add(ValueProducerLookup.getInstance().getValueProducer(refId));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((ConcatenatorValueCombinator) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Infix")) {
                    ((ConcatenatorValueCombinator) vp).setInfix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((ConcatenatorValueCombinator) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="ConcatenatorValueCombinator">
            if (vp instanceof MultiplyValueCombinator) {
                if (name.equalsIgnoreCase(MultiplyValueCombinator.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("ProducerReference")) {
                    //TODO check for self reference
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ((MultiplyValueCombinator) vp).getProducerReferences().add(ValueProducerLookup.getInstance().getValueProducer(refId));
                    return;
                }
                if (name.equalsIgnoreCase("Factor")) {
                    ((MultiplyValueCombinator) vp).setFactor(Long.parseLong(value));
                    return;
                }                
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            // </editor-fold>
            
            // <editor-fold defaultstate="collapsed" desc="ReverseValueModifier">
            if (vp instanceof ReverseValueModifier) {
                if (name.equalsIgnoreCase(ReverseValueModifier.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("ProducerReference")) {
                    //TODO check for self reference
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ((ReverseValueModifier) vp).setProducerReference(ValueProducerLookup.getInstance().getValueProducer(refId));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((ReverseValueModifier) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((ReverseValueModifier) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="SimpleValueReference">
            if (vp instanceof SimpleValueReferencer) {
                if (name.equalsIgnoreCase(SimpleValueReferencer.class.getSimpleName())) {
                    return;
                }
                if (name.equalsIgnoreCase("ProducerReference")) {
                    //TODO check for self reference
                    Long refId = Long.parseLong(value);
                    if (vp.getId() == refId) {
                        throw new SelfReferencingException(refId);
                    }
                    ((SimpleValueReferencer) vp).setProducerReference(ValueProducerLookup.getInstance().getValueProducer(refId));
                    return;
                }
                if (name.equalsIgnoreCase("Prefix")) {
                    ((SimpleValueReferencer) vp).setPrefix(value);
                    return;
                }
                if (name.equalsIgnoreCase("Suffix")) {
                    ((SimpleValueReferencer) vp).setSuffix(value);
                    return;
                }
                throw new NoElementWithNameDefinedException(name, vp.getClass().getSimpleName());

            }
            // </editor-fold>

        } catch (NumberValueProducerExpectedException ex) {
            System.out.println(ex);
        } catch (SelfReferencingException ex) {
            System.out.println(ex);
        } catch (ValueProducerDoesntExistException ex) {
            System.out.println(ex);
        } catch (NoElementWithNameDefinedException ex) {
            System.out.println(ex);
        }
    }
}
